home *** CD-ROM | disk | FTP | other *** search
- /*
- * heap.c -- Simple priority queue. Takes pointers to cost values
- * (presumably the first field in a larger structure) and returns
- * them in increasing order of cost.
- *
- * Copyright (C) 1997 Pretty Good Privacy, Inc.
- *
- * Written by Colin Plumb and Mark H. Weaver
- *
- * $Id: heap.c,v 1.2 1997/07/05 02:55:23 colin Exp $
- */
-
- #include <stdio.h> /* For fprintf(stderr, "Out of memory") */
- #include <stdlib.h> /* For malloc() & co. */
-
- #include "heap.h"
-
- #define HeapParent(i) ((i) / 2)
- #define HeapLeftChild(i) ((i) * 2)
- #define HeapRightChild(i) ((i) * 2 + 1)
- #define HeapElem(h, i) (h)->elems[i]
- #define HeapMinElem(h) HeapElem(h, 1)
- #define HeapElemCost(e) (*(e))
- #define HeapCost(h, i) HeapElemCost(HeapElem(h, i))
- #define HeapSize(h) ((h)->numElems)
-
- static void
- SiftDown(Heap const *heap, HeapCost *e)
- {
- HeapIndex size = HeapSize(heap), parent = 1, child;
- HeapCost cparent = HeapElemCost(e), cchild;
-
- for (;;) {
- child = 2*parent;
- if (child > size)
- break;
- cchild = HeapCost(heap, child);
- if (child < size && cchild > HeapCost(heap, child+1)) {
- cchild = HeapCost(heap, child+1);
- child++;
- }
- if (cparent <= cchild)
- break; /* Stop sifting down */
- HeapElem(heap, parent) = HeapElem(heap, child);
- parent = child;
- }
- HeapElem(heap, parent) = e;
- }
-
- /* Debug tool: verify heap property */
- void
- HeapVerify(Heap *heap)
- {
- HeapIndex i;
-
- for (i = 2; i <= HeapSize(heap); i++)
- if (HeapCost(heap, i) < HeapCost(heap, HeapParent(i)))
- fprintf(stderr, "DEBUG: VerifyHeap failed at elem %d\n", i);
- }
-
- /* Remove and return the minimum cost from the heap. */
- HeapCost *
- HeapGetMin(Heap *heap)
- {
- HeapIndex lastElem = HeapSize(heap);
- HeapCost *retval;
-
- if (!lastElem)
- return NULL;
- retval = HeapMinElem(heap);
- HeapSize(heap) = lastElem-1;
- SiftDown(heap, HeapElem(heap, lastElem));
- return retval;
- }
-
- /* Helper - set heap size, reallocating if needed */
- static void
- HeapResize(Heap *heap, HeapIndex newNumElems)
- {
- if (newNumElems >= heap->elemsAllocated) {
- HeapIndex newAllocSize = heap->elemsAllocated * 2;
-
- if (newAllocSize <= newNumElems)
- newAllocSize = newNumElems + 1;
- heap->elems = (HeapCost **)realloc((void *)heap->elems,
- sizeof(*heap->elems) * newAllocSize);
- if (heap->elems == NULL) {
- fprintf(stderr, "Fatal error: Out of memory growing heap\n");
- exit(1);
- }
- heap->elemsAllocated = newAllocSize;
- }
- heap->numElems = newNumElems;
- }
-
- /* Add an element to the heap */
- void
- HeapInsert(Heap *heap, HeapCost *newElem)
- {
- HeapIndex parent, i = ++HeapSize(heap);
- HeapCost cost = HeapElemCost(newElem);
-
- HeapResize(heap, i);
- /* Sift up until parent = 0 */
- while ((parent = HeapParent(i)) && HeapCost(heap, parent) > cost) {
- HeapElem(heap, i) = HeapElem(heap, parent);
- i = parent;
- }
- heap->elems[i] = newElem;
- }
-
- /* Initialize a new heap */
- void
- HeapInit(Heap *heap, HeapIndex initSize)
- {
- initSize++; /* Add one for temporary element */
- if (initSize < 1)
- initSize = 1;
- heap->elems = (HeapCost **)malloc(initSize * sizeof(*heap->elems));
- if (heap->elems == NULL) {
- fprintf(stderr, "Fatal error: Out of memory creating heap\n");
- exit(1);
- }
- heap->elemsAllocated = initSize;
- heap->numElems = 0;
- }
-
- /* Free up a heap's resources. */
- void
- HeapDestroy(Heap *heap)
- {
- free((void *)heap->elems);
- heap->elemsAllocated = 0;
- heap->numElems = 0;
- heap->elems = NULL;
- }
-
- /*
- * Local Variables:
- * tab-width: 4
- * End:
- * vi: ts=4 sw=4
- * vim: si
- */
-